package br.uniceub.fsw.agenda.model.dao;

import br.uniceub.fsw.agenda.exception.BusinessException;
import br.uniceub.fsw.agenda.exception.DatabaseException;
import br.uniceub.fsw.agenda.exception.UniqueConstraintException;
import br.uniceub.fsw.agenda.model.vo.CidadeVO;
import br.uniceub.fsw.agenda.model.vo.UFVO;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * 05/04/2008
 * @author Rodrigo Uchôa - rodrigo.uchoa@yahoo.com
 * 
 * 26/04/2008
 * @author Bruno Schifer - schifers@gmail.com
 *
 */
public class CidadeDAO extends GenericDAO {
    
    public CidadeDAO(Connection con) {
        super(con);
    }
    
    /**
     * Devolve lista com objetos cidade ordenadas por ordem alfabetica
     * @return
     * @throws BusinessException
     * @throws DatabaseException
     */
    public List<CidadeVO> findAll() throws BusinessException, DatabaseException {
        //string de consulta
        StringBuilder query = new StringBuilder();
        query.append("SELECT * FROM TB_CIDADE ORDER BY NO_CIDADE");
        
        List<CidadeVO> listaRegistros = new ArrayList<CidadeVO>();
        
        try {
            //objeto con é herdado da super classe
            Statement st = this.con.createStatement();
            ResultSet rs = st.executeQuery(query.toString());
            while (rs.next()) {
                CidadeVO cidade = new CidadeVO();
                
                UFVO uf = new UFVO();
                UFDAO ufDAO = new UFDAO(this.con);
                
                uf = ufDAO.findBySigla(rs.getString("SG_UF"));
                
                cidade.setIdCidade(rs.getInt("ID_CIDADE"));
                cidade.setNoCidade(rs.getString("NO_CIDADE"));
                cidade.setUf(uf);
                
                listaRegistros.add(cidade);
            }
            st.close();
            rs.close();
            return listaRegistros;
        } catch (SQLException ex) {
            ex.printStackTrace();
            throw new DatabaseException("Erro ao buscar cidades", ex);
        }        
    }
    
    /**
     * busca todas as cidades de uma UF especifica ordenadas por ordem alfabetica
     * @param siglaUf
     * @return List com objetos cidade
     */
    public List<CidadeVO> findCidadesByUF(String siglaUf)
    throws BusinessException, DatabaseException {
        //query de consulta
        //Para ilustrar o uso de PreparedStatement observe que no lugar
        //do parametro foi colocado um sinal de interrogacao.
        StringBuilder query = new StringBuilder();
        query.append("SELECT * FROM TB_CIDADE");
        query.append(" WHERE SG_UF = ?");
        query.append(" ORDER BY NO_CIDADE");
        
        //lista com registros da consulta
        List<CidadeVO> listaRegistros = new ArrayList<CidadeVO>();
        
        try {
            PreparedStatement st = con.prepareStatement(query.toString());
            //setar a sigla no parametro 1
            st.setString(1, siglaUf);
            
            ResultSet rs = st.executeQuery();
            while (rs.next()) {
                CidadeVO cidade = new CidadeVO();
                cidade.setIdCidade(rs.getInt("ID_CIDADE"));
                cidade.setNoCidade(rs.getString("NO_CIDADE"));

                UFVO uf = new UFVO();
                UFDAO ufDAO = new UFDAO(this.con);
                
                uf = ufDAO.findBySigla(rs.getString("SG_UF"));
                
                cidade.setUf(uf);
                
                listaRegistros.add(cidade);
            }
            st.close();
            rs.close();
            return listaRegistros;            
        } catch (SQLException ex) {
            ex.printStackTrace();
            throw new DatabaseException("Erro no findCidadesByUF()", ex);
        }        
    }
    
    /**
     * Buscar Cidade pelo seu ID (primary key)
     * @param idCidade id da cidade que se deseja buscar
     * @return objeto Cidade
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public CidadeVO findById(Integer idCidade) throws DatabaseException {
        StringBuilder query = new StringBuilder();
        query.append("SELECT * FROM TB_CIDADE WHERE ID_CIDADE = ?");
        
        try {
            PreparedStatement st = con.prepareStatement(query.toString());
            st.setInt(1, idCidade);
            
            ResultSet rs = st.executeQuery();
            CidadeVO cidade = null;
            while (rs.next()) {
                cidade = new CidadeVO();
                cidade.setIdCidade(rs.getInt("ID_CIDADE"));

                UFVO uf = new UFVO();
                UFDAO ufDAO = new UFDAO(this.con);
                
                uf = ufDAO.findBySigla(rs.getString("SG_UF"));
                
                cidade.setUf(uf);

                cidade.setNoCidade(rs.getString("NO_CIDADE"));
            }
            st.close();
            rs.close();
            return cidade;
        } catch (SQLException ex) {
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOCidade.findById()", ex);
        }
    }

    /**
     * Buscar lista de cidades por parte de seu nome
     * @param noCidade parte do nome dos cidades que se deseja buscar
     * @return List de objetos Cidade
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public List<CidadeVO> findAllByNome(String noCidade) throws DatabaseException {
        StringBuilder query = new StringBuilder();
        query.append("SELECT * FROM TB_CIDADE WHERE NO_CIDADE LIKE ? ORDER BY NO_CIDADE");
        
        try {
            PreparedStatement st = con.prepareStatement(query.toString());
            String filtro = "%" + noCidade + "%";
            st.setString(1, filtro);
            
            List<CidadeVO> listaRegistros = new ArrayList<CidadeVO>();
            
            ResultSet rs = st.executeQuery();

            while (rs.next()) {
                CidadeVO cidade = new CidadeVO();
                cidade.setIdCidade(rs.getInt("ID_CIDADE"));
                cidade.setNoCidade(rs.getString("NO_CIDADE"));

                UFVO uf = new UFVO();
                UFDAO ufDAO = new UFDAO(this.con);
                
                uf = ufDAO.findBySigla(rs.getString("SG_UF"));
                
                cidade.setUf(uf);
                
                listaRegistros.add(cidade);
            }
            st.close();
            rs.close();
            return listaRegistros;
        } catch (SQLException ex) {
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOCidade.findAllByNome()", ex);
        }
    }

    /**
     * Buscar lista de cidades por UF
     * @param sgUf sigla da UF das cidades que se deseja buscar
     * @return List de objetos Cidade
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public List<CidadeVO> findAllByUF(String sgUf) throws DatabaseException {
        StringBuilder query = new StringBuilder();
        query.append("SELECT * FROM TB_CIDADE WHERE SG_UF = ? ORDER BY NO_CIDADE");
        
        try {
            PreparedStatement st = con.prepareStatement(query.toString());
            st.setString(1, sgUf);
            
            List<CidadeVO> listaRegistros = new ArrayList<CidadeVO>();
            
            ResultSet rs = st.executeQuery();

            while (rs.next()) {
                CidadeVO cidade = new CidadeVO();
                cidade.setIdCidade(rs.getInt("ID_CIDADE"));
                cidade.setNoCidade(rs.getString("NO_CIDADE"));

                UFVO uf = new UFVO();
                UFDAO ufDAO = new UFDAO(this.con);
                
                uf = ufDAO.findBySigla(rs.getString("SG_UF"));
                
                cidade.setUf(uf);
                
                listaRegistros.add(cidade);
            }
            st.close();
            rs.close();
            return listaRegistros;
        } catch (SQLException ex) {
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOCidade.findAllByUF()", ex);
        }
    }

    /**
     * Buscar lista de cidades pelo nome e por UF
     * @param noCidade nome da Cidade das cidades que se deseja buscar
     * @param sgUf sigla da UF das cidades que se deseja buscar
     * @return List de objetos Cidade
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public List<CidadeVO> findAllByNomeAndUF(String noCidade, String sgUf) throws DatabaseException {
        StringBuilder query = new StringBuilder();
        query.append("SELECT * FROM TB_CIDADE WHERE SG_UF = ? AND NO_CIDADE LIKE ? ORDER BY NO_CIDADE");
        
        try {
            String filtro = "%" + noCidade + "%";
            PreparedStatement st = con.prepareStatement(query.toString());
            st.setString(1, sgUf);
            st.setString(2, filtro);
            
            List<CidadeVO> listaRegistros = new ArrayList<CidadeVO>();
            
            ResultSet rs = st.executeQuery();

            while (rs.next()) {
                CidadeVO cidade = new CidadeVO();
                cidade.setIdCidade(rs.getInt("ID_CIDADE"));
                cidade.setNoCidade(rs.getString("NO_CIDADE"));

                UFVO uf = new UFVO();
                UFDAO ufDAO = new UFDAO(this.con);
                
                uf = ufDAO.findBySigla(rs.getString("SG_UF"));
                
                cidade.setUf(uf);
                
                listaRegistros.add(cidade);
            }
            st.close();
            rs.close();
            return listaRegistros;
        } catch (SQLException ex) {
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOCidade.findAllByUF()", ex);
        }
    }

    /**
     * Faz o insert de um novo cidade e devolve a o id recem gerado
     * @param Cidade cidade que se deseja inserir
     * @return ID auto-increment gerado para esse registro
     * @throws br.uniceub.fsw.agenda.exception.BusinessException
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public Integer insert(CidadeVO cidade) throws BusinessException, DatabaseException {        
        StringBuilder query = new StringBuilder();
        query.append("INSERT INTO TB_CIDADE(NO_CIDADE, SG_UF) ");
        query.append("VALUES (?,?)");
        
        //retornar id gerado
        Integer generatedId = null;
        
        try {           
            PreparedStatement st = con.prepareStatement(query.toString());
            st.setString(1, cidade.getNoCidade());
            st.setString(2, cidade.getUf().getSgUf());
            
            st.executeUpdate();
            
            //pegar id gerado
            ResultSet rs = st.getGeneratedKeys();
            while (rs.next()) {
                generatedId = new Integer(rs.getString(1));                
            }                    
            
            return generatedId;            
        } catch (SQLException ex) {            
            ex.printStackTrace();
            if (ex.getErrorCode() == 1062) {
                throw new UniqueConstraintException(ex.getMessage(), ex);                
            }
            throw new DatabaseException("Erro no DAOCidade.insert()", ex);            
        }      
    }
    
    /**
     * Faz o update de uma cidade
     * @param Cidade cidade que se deseja alterar
     * @throws br.uniceub.fsw.agenda.exception.BusinessException
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public void update(CidadeVO cidade) throws BusinessException, DatabaseException {        
        StringBuilder query = new StringBuilder();
        query.append("UPDATE TB_CIDADE SET NO_CIDADE = ?, SG_UF = ? ");
        query.append("WHERE ID_CIDADE = ?");
        
        try {           
            PreparedStatement st = con.prepareStatement(query.toString());
            st.setString(1, cidade.getNoCidade());
            st.setString(2, cidade.getUf().getSgUf());
            st.setString(3, cidade.getIdCidade().toString());
            
            st.executeUpdate();
        } catch (SQLException ex) {            
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOCidade.update()", ex);
        }      
    }
    
    /**
     * Faz o delete de um cidade
     * @param Cidade cidade que se deseja excluir
     * @throws br.uniceub.fsw.agenda.exception.BusinessException
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public void delete(CidadeVO cidade) throws BusinessException, DatabaseException {        
        StringBuilder query = new StringBuilder();
        query.append("DELETE FROM TB_CIDADE ");
        query.append("WHERE ID_CIDADE = ?");
        
        try {           
            PreparedStatement st = con.prepareStatement(query.toString());
            st.setString(1, cidade.getIdCidade().toString());
            
            st.executeUpdate();
        } catch (SQLException ex) {            
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOCidade.delete()", ex);            
        }      
    }

}
